package com.qinglei.recoup.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.JsonNode;
import com.qinglei.recoup.common.domain.RadarUserDataFour;
import com.qinglei.recoup.common.domain.*;
import com.qinglei.recoup.common.exception.RedisConnectException;
import com.qinglei.recoup.common.service.RedisService;
import com.qinglei.recoup.common.tenant.TenantContextHolder;
import com.qinglei.recoup.common.utils.DateUtil;
import com.qinglei.recoup.common.utils.JsonUtils;
import com.qinglei.recoup.common.utils.RecoupUtil;
import com.qinglei.recoup.common.utils.TreeUtil;
import com.qinglei.recoup.system.dao.BedHealthStateMapper;
import com.qinglei.recoup.system.dao.BedMapper;
import com.qinglei.recoup.system.dao.FlagBodyMovementMapper;
import com.qinglei.recoup.system.dao.RadarBedMapper;
import com.qinglei.recoup.system.domain.*;
import com.qinglei.recoup.system.domain.vo.RadarBedVo;
import com.qinglei.recoup.system.enums.BedStatusEnum;
import com.qinglei.recoup.system.enums.EventEnum;
import com.qinglei.recoup.system.enums.RoleEnum;
import com.qinglei.recoup.system.pojo.*;
import com.qinglei.recoup.system.pojo.event.EventDto;
import com.qinglei.recoup.system.service.*;
import com.qinglei.recoup.system.util.ProducerInstance;
import com.qinglei.recoup.third.event.AlarmInfoEvent;
import com.qinglei.recoup.third.properties.FuXingProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.MQProducer;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author syp
 */
@Service
@Slf4j
public class BedServiceImpl extends ServiceImpl<BedMapper, Bed> implements BedService {

    /**
     * 默认离床超时时间 单位秒
     */
    public static final int OUT_BED_TIMEOUT_DEF = 300;
    @Value("${alarm-event-topic}")
    private String alarmTopic;
    @Value("${alarm-event-group}")
    private String alarmGroup;
    @Value("${rocketmq.name-server}")
    private String rocketServer;


    @Resource
    private RoomService roomService;

    @Resource
    private FloorService floorService;

    @Resource
    private BuildingService buildingService;

    @Resource
    @Lazy
    private EventLogService eventLogService;

    @Resource
    private EventWsService eventWsService;

    @Resource
    private RedisService redisService;

    @Resource
    private EventService eventService;

    @Resource
    private EventProcService eventProcService;

    @Autowired
    private BedMonitorTimeService bedMonitorTimeService;

    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private NurseBedService nurseBedService;

    @Autowired
    private DeanBedService deanBedService;

    @Resource
    private FlagBodyMovementMapper flagBodyMovementMapper;


    @Resource
    private BedHealthStateMapper bedHealthStateMapper;

    @Value("${Health.onOrOffV4}")
    private boolean onOrOffV4;

    @Resource
    private EventLogTestService eventLogTestService;
    @Resource
    private RadarBedService radarBedService;

    @Autowired
    private ApplicationContext applicationContext;

    @Resource
    private FuXingProperties fuXingProperties;

    @Override
    public CommonRes<IPage<BedShowVO>> showPageBed(BedPageParam bedPageParam) {
        Page<BedShowVO> page = new Page<>(bedPageParam.getPageNum(), bedPageParam.getPageSize());

        IPage<BedShowVO> bedShowVOIPage = this.baseMapper.showPageFloor(page, bedPageParam.getRoomId());
        return CommonRes.ok(bedShowVOIPage);
    }

    @Override
    public List<BedStatusVO> getBedShowListByUser(Long userId, Integer roleId) {
        List<BedStatusVO> resList = new ArrayList<>();
        List<Integer> bedIdsByUser = this.getBedIdsByUser(userId, roleId);
        if (CollectionUtils.isEmpty(bedIdsByUser) || bedIdsByUser.get(0) == 0) {
            return resList;
        }
        if (bedIdsByUser.get(0) == -1) {
            bedIdsByUser = null;
        }
        Integer tenantId = TenantContextHolder.getTenantId();
        List<BedStatusBO> bedStatusBOS = this.baseMapper.selectBedStatusListByIds(bedIdsByUser, tenantId);
        List<Integer> bedIds = bedStatusBOS.stream().map(BedStatusBO::getBedId).collect(Collectors.toList());
        Map<Integer, RadarBedVo> radarBedMapByBedIds = radarBedService.getRadarBedMapByBedIds(bedIds);
        bedStatusBOS.forEach(bedStatusBO -> {
            BedStatusVO bedStatusVO = new BedStatusVO();
            BeanUtils.copyProperties(bedStatusBO, bedStatusVO);
            setByStatus(bedStatusBO, bedStatusVO);
            if (bedStatusBO.getHealthyBpm() != null && bedStatusVO.getStatus() == BedStatusEnum.NORMAL.getCode()) {
                switch (bedStatusBO.getHealthyBpm()) {
                    case BedHealthState.SUB_STATUS_BREATH_NORMAL:
                        bedStatusVO.setHealthyStatusName("呼吸正常");
                        break;
                    case BedHealthState.SUB_STATUS_BREATH_HIGHT:
                        bedStatusVO.setHealthyStatusName("呼吸过速");
                        break;
                    case BedHealthState.SUB_STATUS_BREATH_LOW:
                        bedStatusVO.setHealthyStatusName("呼吸暂停过久");
                        break;
                    case BedHealthState.SUB_STATUS_HEART_NORMAL:
                        bedStatusVO.setHealthyStatusName("心跳正常");
                        break;
                    case BedHealthState.SUB_STATUS_HEART_HIGHT:
                        bedStatusVO.setHealthyStatusName("心跳过速");
                        break;
                    case BedHealthState.SUB_STATUS_HEART_LOW:
                        bedStatusVO.setHealthyStatusName("心跳过缓");
                        break;
                    default:
                }
                Long eventId = bedStatusBO.getEventId();
                Integer bedId = bedStatusBO.getBedId();
                QueryWrapper queryWrapper = new QueryWrapper();
                queryWrapper.eq("event_id", eventId);
                queryWrapper.eq("bed_id", bedId);
                EventProc eventProc = eventProcService.getOne(queryWrapper);
                if (eventProc != null && eventProc.getStatus() == 3) {
                    bedStatusVO.setHealthyBpm(BedHealthState.SUB_STATUS_PROCESSING);
                }

            } else {
                bedStatusVO.setHealthyBpm(null);
            }
            if (radarBedMapByBedIds.containsKey(bedStatusBO.getBedId())) {
                bedStatusVO.setSn(radarBedMapByBedIds.get(bedStatusBO.getBedId()).getSnCode());
            }
            // 设置遗漏任务数量
//            bedStatusVO.setMissedEventNum(eventProcService.getMissedEventNumByBed(bedStatusVO.getBedId()));
            resList.add(bedStatusVO);
        });

        return resList;
    }

    /**
     * 获取用户对应的床位ID列表
     *
     * @param userId
     * @param roleId
     * @return 列表中第一个元素为0表示无对应床位，为-1表示全部床位，其他为床位ID
     */
    @Override
    public List<Integer> getBedIdsByUser(Long userId, Integer roleId) {
        List<Integer> ret = new ArrayList<>();
        if (roleId == RoleEnum.NURSE.getCode()) {
            List<NurseBed> nurseBeds = nurseBedService.list(Wrappers.<NurseBed>lambdaQuery().select(NurseBed::getBedId).eq(NurseBed::getUserId, userId));
            if (CollectionUtils.isEmpty(nurseBeds)) {
                ret.add(0);
            } else {
                ret = nurseBeds.stream().map(NurseBed::getBedId).collect(Collectors.toList());
            }
        } else if (roleId == RoleEnum.WARDEN.getCode()) {
            List<DeanBed> deanBeds = deanBedService.list(Wrappers.<DeanBed>lambdaQuery()
                    .select(DeanBed::getType, DeanBed::getObjId)
                    .eq(DeanBed::getUserId, userId)
                    .orderByDesc(DeanBed::getType));
            if (CollectionUtils.isEmpty(deanBeds)) {
                ret.add(0);
            } else if (deanBeds.get(0).getType() == BedService.TYPE_ROOT) {
                ret.add(-1);
            } else {
                List<Integer> buildingIds = new ArrayList<>();
                List<Integer> floorIds = new ArrayList<>();
                List<Integer> roomIds = new ArrayList<>();
                List<Integer> bedIds = new ArrayList<>();
                for (DeanBed deanBed : deanBeds) {
                    switch (deanBed.getType()) {
                        case BedService.TYPE_BED:
                            bedIds.add(deanBed.getObjId());
                            break;
                        case BedService.TYPE_ROOM:
                            roomIds.add(deanBed.getObjId());
                            break;
                        case BedService.TYPE_FLOOR:
                            floorIds.add(deanBed.getObjId());
                            break;
                        case BedService.TYPE_BUILDING:
                            buildingIds.add(deanBed.getObjId());
                            break;
                    }
                }
                List<Integer> bedIds4Dean = getBedIds4Dean(buildingIds, floorIds, roomIds, bedIds);
                if (CollectionUtils.isEmpty(bedIds4Dean)) {
                    ret.add(0);
                } else {
                    ret = bedIds4Dean;
                }
            }
        } else {
            ret.add(0);
        }
        return ret;
    }

    /**
     * 获取院长对应的床位
     *
     * @param buildingIds
     * @param floorIds
     * @param roomIds
     * @param bedIds
     * @return
     */
    private List<Integer> getBedIds4Dean(List<Integer> buildingIds, List<Integer> floorIds,
                                         List<Integer> roomIds, List<Integer> bedIds) {
        Set<Integer> bedIdsSet = new HashSet<>();
        if (CollectionUtils.isNotEmpty(buildingIds)) {
            List<Bed> beds = baseMapper.selectList(Wrappers.<Bed>lambdaQuery().in(Bed::getBuildingId, buildingIds));
            for (Bed bed : beds) {
                bedIdsSet.add(bed.getId());
            }
        }
        if (CollectionUtils.isNotEmpty(floorIds)) {
            List<Bed> beds = baseMapper.selectList(Wrappers.<Bed>lambdaQuery().in(Bed::getFloorId, floorIds));
            for (Bed bed : beds) {
                bedIdsSet.add(bed.getId());
            }
        }
        if (CollectionUtils.isNotEmpty(roomIds)) {
            List<Bed> beds = baseMapper.selectList(Wrappers.<Bed>lambdaQuery().in(Bed::getRoomId, roomIds));
            for (Bed bed : beds) {
                bedIdsSet.add(bed.getId());
            }
        }
        if (CollectionUtils.isNotEmpty(bedIds)) {
            bedIdsSet.addAll(bedIds);
        }

        return new ArrayList<>(bedIdsSet);
    }

    private void setByStatus(BedStatusBO bedStatusBO, BedStatusVO bedStatusVO) {

        // 获取当前监测时段
        BedMonitorTimeVO bedCurMonitorTime = this.getBedCurMonitorTime(bedStatusBO.getBedId());

        if (Bed.RADAR_OFFLINE == bedStatusBO.getIsRadarOnline()) {
            // 设备离线
            bedStatusVO.setStatus(BedStatusEnum.DEVICE_OFFLINE.getCode());
            bedStatusVO.setStatusName(BedStatusEnum.DEVICE_OFFLINE.getName());
            bedStatusVO.setSubStatus(0);
            if (bedCurMonitorTime != null) {
                bedStatusVO.setCurMonitorTime(bedCurMonitorTime.getStartTime() + '-' + bedCurMonitorTime.getEndTime());
            }
        } else if (bedStatusBO.getRadarType() == Radar.TYPE_BED && bedStatusBO.getIsRadarOn() == Bed.RADAR_OFF) {
            // 监测仪关闭
            bedStatusVO.setStatus(BedStatusEnum.MONITOR_OFF.getCode());
            bedStatusVO.setStatusName(BedStatusEnum.MONITOR_OFF.getName());
            bedStatusVO.setDescription(bedStatusBO.getRemarks());
            bedStatusVO.setMissedEventNum(eventProcService.getMissedEventNumByBed(bedStatusBO.getBedId()));
        } else if (bedStatusBO.getRadarType() == Radar.TYPE_BED && bedCurMonitorTime == null) {
            // 不在监测时段
            bedStatusVO.setStatus(BedStatusEnum.NON_IN_MONITOR.getCode());
            bedStatusVO.setStatusName(BedStatusEnum.NON_IN_MONITOR.getName());
            bedStatusVO.setMissedEventNum(eventProcService.getMissedEventNumByBed(bedStatusBO.getBedId()));
            BedMonitorTimeVO nextMonitorTime = bedMonitorTimeService.getNextMonitorTime(bedStatusBO.getBedId());
            if (nextMonitorTime != null) {
                bedStatusVO.setCurMonitorTime(nextMonitorTime.getStartTime() + '-' + nextMonitorTime.getEndTime());
            }
        } else if (Bed.STATUS_ALARM == bedStatusBO.getStatus()) {

            if (bedStatusBO.getHappenTime() != null) {
                int duration = (int) (LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) -
                        bedStatusBO.getHappenTime().toEpochSecond(ZoneOffset.of("+8")));
                bedStatusVO.setDuration(duration);
            } else {
                bedStatusVO.setDuration(0);
            }
            // 在监测时段，设置监测时间
            if (bedStatusBO.getRadarType() == Radar.TYPE_BED) {
                bedStatusVO.setCurMonitorTime(bedCurMonitorTime.getStartTime() + '-' + bedCurMonitorTime.getEndTime());
            }
            System.err.println(bedStatusBO);
            // 是否报警
            if (null != bedStatusBO.getEventStatus()) {
                if (EventProc.STATUS_HAPPEN == bedStatusBO.getEventStatus() || EventProc.STATUS_PROCESSING == bedStatusBO.getEventStatus()) {
                    // 报警发生
                    bedStatusVO.setStatus(BedStatusEnum.ALARM.getCode());
                    if (bedStatusBO.getRadarType() == Radar.TYPE_BED) {
                        bedStatusVO.setSubStatus(BedStatusEnum.AlarmEnum.OUT_BED_TOO_LONG.getCode());
                        bedStatusVO.setStatusName(BedStatusEnum.AlarmEnum.OUT_BED_TOO_LONG.getName());
                    } else {
                        bedStatusVO.setSubStatus(BedStatusEnum.AlarmEnum.FALL_DOWN.getCode());
                        bedStatusVO.setStatusName(BedStatusEnum.AlarmEnum.FALL_DOWN.getName());
                    }
                } else if (EventProc.STATUS_FINISHED == bedStatusBO.getEventStatus()) {
                    // 处理中
                    bedStatusVO.setStatus(BedStatusEnum.PROCESSING.getCode());
                    if (bedStatusBO.getRadarType() == Radar.TYPE_BED) {
                        bedStatusVO.setStatusName(BedStatusEnum.AlarmEnum.OUT_BED_TOO_LONG.getName());
                    } else {
                        bedStatusVO.setStatusName(BedStatusEnum.AlarmEnum.FALL_DOWN.getName());
                    }
                } else {
                    log.warn("error alarm status:{}", bedStatusBO);
                }
            }
        } else if (Bed.STATUS_NORMAL == bedStatusBO.getStatus()) {
            // 在监测时段，设置监测时间
            if (bedStatusBO.getRadarType() == Radar.TYPE_BED) {
                bedStatusVO.setCurMonitorTime(bedCurMonitorTime.getStartTime() + '-' + bedCurMonitorTime.getEndTime());
            }
            bedStatusVO.setStatus(BedStatusEnum.NORMAL.getCode());
            bedStatusVO.setMissedEventNum(eventProcService.getMissedEventNumByBed(bedStatusBO.getBedId()));
            if (Bed.SUB_STATUS_OUT_BED == bedStatusBO.getSubStatus()) {
                bedStatusVO.setSubStatus(BedStatusEnum.NormalEnum.OUT_BED.getCode());
                bedStatusVO.setStatusName(BedStatusEnum.NormalEnum.OUT_BED.getName());
                if (bedStatusBO.getHappenTime() == null) {
                    bedStatusBO.setHappenTime(LocalDateTime.now());
                    log.warn("HappenTime in null bedStatusBO:{}", bedStatusBO);
                }
                int duration = (int) (LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) -
                        bedStatusBO.getHappenTime().toEpochSecond(ZoneOffset.of("+8")));
                bedStatusVO.setDuration(Math.max(duration, 1));
            } else if (Bed.SUB_STATUS_CLEAR == bedStatusBO.getSubStatus()) {  //清醒
                bedStatusVO.setSubStatus(BedStatusEnum.NormalEnum.CLEAR.getCode());
                bedStatusVO.setStatusName(BedStatusEnum.NormalEnum.CLEAR.getName());
//                    QueryWrapper queryWrapper = new QueryWrapper();
//                    queryWrapper.eq("bed_id",bedStatusBO.getBedId());
//                    BedHealthState bedHealthState = bedHealthStateMapper.selectOne(queryWrapper);
//                    if(bedHealthState!=null){
//                        bedStatusVO.setHealthyBpm(bedHealthState.getType());
//
//                        if(bedHealthState.getType() == BedHealthState.SUB_STATUS_BREATH_HIGHT){
//                            bedStatusVO.setHealthyStatusName("呼吸过速");
//                        }
//                        if(bedHealthState.getType() ==  BedHealthState.SUB_STATUS_BREATH_LOW){
//                            bedStatusVO.setHealthyStatusName("呼吸暂停过久");
//                        }
//                        if(bedHealthState.getType() == BedHealthState.SUB_STATUS_HEART_HIGHT){
//                            bedStatusVO.setHealthyStatusName("心跳过速");
//                        }
//                        if(bedHealthState.getType() == BedHealthState.SUB_STATUS_HEART_LOW){
//                            bedStatusVO.setHealthyStatusName("心跳过缓");
//                        }
//
//                    }
                this.setBedHealthState(bedStatusBO.getBedId(), bedStatusVO);

                this.setBedHealthState(bedStatusBO.getBedId(), bedStatusVO);
            } else if (Bed.SUB_STATUS_LIGHT_SLEEP == bedStatusBO.getSubStatus()) {
                bedStatusVO.setSubStatus(BedStatusEnum.NormalEnum.LIGHT_SLEEP.getCode());
                bedStatusVO.setStatusName(BedStatusEnum.NormalEnum.LIGHT_SLEEP.getName());
                this.setBedHealthState(bedStatusBO.getBedId(), bedStatusVO);
            } else if (Bed.SUB_STATUS_DEEP_SLEEP == bedStatusBO.getSubStatus()) {
                bedStatusVO.setSubStatus(BedStatusEnum.NormalEnum.DEEP_SLEEP.getCode());
                bedStatusVO.setStatusName(BedStatusEnum.NormalEnum.DEEP_SLEEP.getName());
                this.setBedHealthState(bedStatusBO.getBedId(), bedStatusVO);
            } else if (Bed.SUB_STATUS_EXIST_NONE == bedStatusBO.getSubStatus()) {
                bedStatusVO.setSubStatus(BedStatusEnum.NormalEnum.EXIST_NONE.getCode());
                bedStatusVO.setStatusName(BedStatusEnum.NormalEnum.EXIST_NONE.getName());
            } else if (Bed.SUB_STATUS_EXIST_SOMEONE == bedStatusBO.getSubStatus()) {
                bedStatusVO.setSubStatus(BedStatusEnum.NormalEnum.EXIST_SOMEONE.getCode());
                bedStatusVO.setStatusName(BedStatusEnum.NormalEnum.EXIST_SOMEONE.getName());
            } else {
                log.warn("error normal status:{}", bedStatusBO);
                bedStatusVO.setSubStatus(BedStatusEnum.NormalEnum.CLEAR.getCode());
                bedStatusVO.setStatusName(BedStatusEnum.NormalEnum.CLEAR.getName());
            }
        } else {
            log.warn("error status:{}", bedStatusBO);
        }
    }

    private void setBedHealthState(Integer bedId, BedStatusVO bedStatusVO) {
        BedHealthState bedHealthState = bedHealthStateMapper.selectOne(new QueryWrapper<BedHealthState>().lambda()
                .eq(BedHealthState::getBedId, bedId).last("LIMIT 1"));
        if (bedHealthState != null) {
            bedStatusVO.setHealthyBpm(bedHealthState.getType());
            if (bedHealthState.getType() == BedHealthState.SUB_STATUS_BREATH_HIGHT) {
                bedStatusVO.setHealthyStatusName("呼吸过速");
            }
            if (bedHealthState.getType() == BedHealthState.SUB_STATUS_BREATH_LOW) {
                bedStatusVO.setHealthyStatusName("呼吸暂停过久");
            }
            if (bedHealthState.getType() == BedHealthState.SUB_STATUS_HEART_HIGHT) {
                bedStatusVO.setHealthyStatusName("心跳过速");
            }
            if (bedHealthState.getType() == BedHealthState.SUB_STATUS_HEART_LOW) {
                bedStatusVO.setHealthyStatusName("心跳过缓");
            }

        }
    }

    @Override
    public Tree<Bed> getBedTree(BedTreeAttachBO disableData) {
        return getBedTree(disableData, false);
    }

    @Override
    public Tree<Bed> getBedTree(BedTreeAttachBO disableData, boolean addTotal) {
        List<Bed> listBed = this.baseMapper.selectList(Wrappers.emptyWrapper());
        if (CollectionUtils.isEmpty(listBed)) {
            return TreeUtil.build(new ArrayList<>());
        }
        Set<Integer> setRoomIds = new HashSet<>();
        Set<Integer> setFloorIds = new HashSet<>();
        Set<Integer> setBuildingIds = new HashSet<>();
        listBed.forEach(bed -> {
            setRoomIds.add(bed.getRoomId());
            setFloorIds.add(bed.getFloorId());
            setBuildingIds.add(bed.getBuildingId());
        });

        Collection<Room> rooms = roomService.listByIds(setRoomIds);
        Collection<Floor> floors = floorService.listByIds(setFloorIds);
        Collection<Building> buildings = buildingService.listByIds(setBuildingIds);

        List<Tree<Bed>> listTree = new ArrayList<>(listBed.size() + rooms.size() + floors.size() + buildings.size());

        listBed.forEach(bed -> {
            Tree<Bed> node = new Tree<>();
            node.setId(bed.getId().toString());
            node.setKey(node.getId());
            node.setTitle(bed.getName());
            node.setType(String.valueOf(TYPE_BED));
            node.setParentId(TREE_ROOM_PREFIX + bed.getRoomId());
            node.setValue("1");
            if (disableData.getBedIds() != null && disableData.getBedIds().contains(bed.getId())) {
                node.setUsable(true);
                node.setDisabled(true);
            }
            listTree.add(node);
        });
        boolean suffixBedNum = disableData.isSuffixBedNum();
        rooms.forEach(room -> {
            Tree<Bed> node = new Tree<>();
            node.setId(TREE_ROOM_PREFIX + room.getId().toString());
            node.setKey(node.getId());
            String title = suffixBedNum ? room.getName() + "（" + room.getBedCnt() + "床位）" : room.getName();
            node.setTitle(title);
            node.setType(String.valueOf(TYPE_ROOM));
            node.setParentId(TREE_FLOOR_PREFIX + room.getFloorId());
            node.setValue(room.getBedCnt().toString());
            if (disableData.getRoomIds() != null && disableData.getRoomIds().contains(room.getId())) {
                node.setUsable(true);
                node.setDisabled(true);
            }
            listTree.add(node);
        });

        floors.forEach(floor -> {
            Tree<Bed> node = new Tree<>();
            node.setId(TREE_FLOOR_PREFIX + floor.getId().toString());
            node.setKey(node.getId());
            String title = suffixBedNum ? floor.getName() + "（" + floor.getBedCnt() + "床位）" : floor.getName();
            node.setTitle(title);
            node.setType(String.valueOf(TYPE_FLOOR));
            node.setParentId(TREE_BUILDING_PREFIX + floor.getBuildingId());
            node.setValue(floor.getBedCnt().toString());
            if (disableData.getFloorIds() != null && disableData.getFloorIds().contains(floor.getId())) {
                node.setUsable(true);
                node.setDisabled(true);
            }
            listTree.add(node);
        });

        Integer bedCnt = 0;
        for (Building building : buildings) {
            Tree<Bed> node = new Tree<>();
            node.setId(TREE_BUILDING_PREFIX + building.getId().toString());
            node.setKey(node.getId());
            String title = suffixBedNum ? building.getName() + "（" + building.getBedCnt() + "床位）" : building.getName();
            node.setTitle(title);
            node.setType(String.valueOf(TYPE_BUILDING));
            if (addTotal) {
                node.setParentId(TREE_ALL_ID);
            } else {
                node.setParentId(null);
            }
            node.setValue(building.getBedCnt().toString());
            bedCnt += building.getBedCnt();
            if (disableData.getBuildingIds() != null && disableData.getBuildingIds().contains(building.getId())) {
                node.setUsable(true);
                node.setDisabled(true);
            }
            listTree.add(node);
        }
        if (addTotal) {
            Tree<Bed> node = new Tree<>();
            node.setId(TREE_ALL_ID);
            node.setKey(node.getId());
            String title = suffixBedNum ? "全部床位" + "（" + bedCnt + "床位）" : "全部床位";
            node.setTitle(title);
            node.setType(String.valueOf(TYPE_ROOT));
            node.setParentId(null);
            node.setValue(bedCnt.toString());
            if (disableData.getHasTotal() != null && disableData.getHasTotal()) {
                node.setUsable(true);
                node.setDisabled(true);
            }
            listTree.add(node);
        }

        Tree<Bed> rootNode = TreeUtil.build(listTree);
        if (rootNode != null) {
            rootNode.setValue(bedCnt.toString());
        }
        return rootNode;
    }

    /**
     * 床位检测仪关闭备注
     *
     * @param bedRemarksParam
     * @return
     */
    @Override
    public CommonRes radarCloseRemark(BedRemarksParam bedRemarksParam) {
        Bed bed = this.baseMapper.selectById(bedRemarksParam.getBedId());
        if (bed == null) {
            return CommonRes.failed("床位不存在");
        }
        if (bed.getIsRadarOn() != Bed.RADAR_OFF) {
            return CommonRes.failed("监测仪未处于关闭状态");
        }
        Bed bedUpdate = new Bed();
        bedUpdate.setId(bedRemarksParam.getBedId());
        bedUpdate.setRemarks(bedRemarksParam.getRemarks());
        int count = baseMapper.updateById(bedUpdate);
        if (count <= 0) {
            return CommonRes.failed("床位监测仪关闭备注失败");
        }
        return CommonRes.ok();
    }

    /**
     * 床位监测仪开启或关闭
     *
     * @param param
     * @return
     */
    @Override
    public CommonRes onOffMonitor(OnOffMonitorParam param) {
        Bed bed = this.baseMapper.selectById(param.getBedId());
        if (bed == null) {
            return CommonRes.failed("床位不存在");
        }
        if (param.getOnOff().equals(bed.getIsRadarOn())) {
            return CommonRes.failed("监测仪开关状态不正确");
        }
        int eventType;
        if (param.getOnOff() == Bed.RADAR_OFF) {
            // 关闭监测仪
            eventType = EventEnum.MONITOR_SWITCH_OFF.getCode();
        } else {
            // 开启监测仪
            eventType = EventEnum.MONITOR_SWITCH_ON.getCode();
        }
        Bed bedUpdate = new Bed();
        bedUpdate.setId(bed.getId());
        bedUpdate.setIsRadarOn(param.getOnOff());
        int count = baseMapper.updateById(bedUpdate);
        if (count <= 0) {
            return CommonRes.failed("监测仪开关失败");
        }

        // 开启监控时
        if (bed.getIsRadarOn() == Bed.RADAR_ON) {
            // 恢复离床计时
            this.resumeOutBedTime(bed);
        }
        // 记录事件
        eventLogService.procEventLog(bedUpdate.getId(), RecoupUtil.getCurrentUser().getId(),
                null, eventType, null, TenantContextHolder.getTenantId());
        // 推送床位当前状态
        this.pushBedCurStatus(bed.getId());

        return CommonRes.ok();
    }

    @Override
    public BedBO getBedFullName(Integer bedId) {
        return this.baseMapper.selectBedFullName(bedId);
    }

    /**
     * 获取床位列表（名称和ID）
     *
     * @return
     */
    @Override
    public List<BedVO> getBedNameList() {
        List<BedVO> bedVOList = new ArrayList<>();
        User currentUser = RecoupUtil.getCurrentUser();
        Long userId = currentUser.getId();
        Integer roleId = Integer.parseInt(currentUser.getRoleId());
        List<Integer> bedIdsByUser = this.getBedIdsByUser(userId, roleId);
        if (CollectionUtils.isEmpty(bedIdsByUser) || bedIdsByUser.get(0) == 0) {
            return bedVOList;
        }
        if (bedIdsByUser.get(0) == -1) {
            bedIdsByUser = null;
        }

        Integer tenantId = TenantContextHolder.getTenantId();
        List<BedBO> bedBOS = this.baseMapper.selectBedList(bedIdsByUser, tenantId);
        if (CollectionUtils.isNotEmpty(bedBOS)) {
            bedVOList = bedBOS.stream().map(item -> {
                BedVO bedVO = new BedVO();
                bedVO.setBedId(item.getBedId());
                bedVO.setBedName(item.getFloorName() + "-" + item.getRoomName() + "-" + item.getBedName());
                return bedVO;
            }).collect(Collectors.toList());
        }

        return bedVOList;
    }

    /**
     * 处理监测仪上传的和床位有关的数据
     *
     * @param message
     */
    @Override
    public void procRadarData(RadarMessage message, boolean isTask) throws MQBrokerException, RemotingException, InterruptedException, MQClientException {
        String sn = message.getSn();
        Bed bed = this.baseMapper.selectBySn(message.getSn());
        if (bed == null) {
            log.debug("procRadarData not bind bed sn: {}", message.getSn());
            return;
        }
        //设备状态
        if (message.getType() == RadarMessage.TYPE_DEVICE_STATUS) {
            Integer devStatus = (Integer) message.getData();
            // 不处理设备主动上传的状态消息，仅通过检查设备最后上传数据的时间设置离线上线状态
            if (RadarMessage.STATUS_ONLINE == devStatus ||
                    (RadarMessage.STATUS_OFFLINE == devStatus && !isTask)) {
                log.debug("procRadarData not bind bed sn: {}", message.getSn());
                return;
            }
            this.prodDeviceStatus(bed, devStatus);
        } else if (message.getType() == RadarMessage.TYPE_USER_DATA) {  //用户数据
            this.procUserData(bed, (RadarUserDataDTO) message.getData());
        } else if (message.getType() == RadarMessage.TYPE_FALL_DOWN_DATA) {  //跌倒数据
//            RadarFallDownDataDTO radarFallDownDataDTO = (RadarFallDownDataDTO) message.getData();
//            if (radarFallDownDataDTO.getExist() == 1 && radarFallDownDataDTO.getL2() == 1) {
//                //推送跌倒报警
//                EventDto eventDto = new EventDto(10, bed.getName(), sn, new Date(), "跌倒报警");
//                eventDto.setUuid(UUID.randomUUID().toString().replaceAll("-", ""));
//                MQProducer producer = ProducerInstance.getProducerInstance().getInstance(rocketServer, alarmGroup);
////                DefaultMQProducer producer = new DefaultMQProducer(alarmGroup);
//                Message msg = new Message(alarmTopic, JSON.toJSONString(eventDto).getBytes(StandardCharsets.UTF_8));
//                producer.sendOneway(msg);
////                rocketMQTemplate.convertAndSend(rocketTopic, eventDto);
//            }
            this.procFallDownData(bed, (RadarFallDownDataDTO) message.getData(), sn);
        }
    }

    @Override
    public void procRadarData(String sn, RadarFallDownDataDTO data) {
        Bed bed = this.baseMapper.selectBySn(sn);
        this.procFallDownData(bed, data, sn);
    }

    /**
     * 处理跌倒数据
     *
     * @param bed
     * @param data
     */
    private void procFallDownData(Bed bed, RadarFallDownDataDTO data, String sn) {
        Bed bedUpdate = new Bed();
        boolean isUpdate = false;
        boolean isPush = false;
        boolean isLog = false;
        int eventType = 0;
        if (bed.getIsRadarOnline() == Bed.RADAR_OFFLINE) {
            bedUpdate.setIsRadarOnline(Bed.RADAR_ONLINE);
            // 记录事件日志 雷达上线
            eventLogService.procEventLog(bed.getId(), null, null, EventEnum.MONITOR_ONLINE.getCode(), null, bed.getTenantId());
            isUpdate = true;
            isPush = true;
        }
        if (bed.getStatus() == Bed.STATUS_NORMAL) {
            // 如果子状态有变化,修改状态
            if (data.getL2() != 0) {
                // 跌倒报警
                try {
                    //推送跌倒报警
                    log.info("触发跌倒报警  ==>" + sn);
                    EventDto eventDto = new EventDto(10, bed.getName(), sn, new Date(), "跌倒报警");
                    eventDto.setUuid(UUID.randomUUID().toString().replaceAll("-", ""));
                    MQProducer producer = ProducerInstance.getProducerInstance().getInstance(rocketServer, alarmGroup);
                    Message msg = new Message(alarmTopic, JSON.toJSONString(eventDto).getBytes(StandardCharsets.UTF_8));
                    producer.sendOneway(msg);
                } catch (Exception e) {
                    log.error("推送跌倒报警异常 ==>{}", e.getMessage());
                }

                Event event = new Event();
                event.setBedId(bed.getId());
                event.setHappenTime(LocalDateTime.now());
                event.setType(Bed.SUB_STATUS_FALL_DOWN);
                this.procAlarmEvent4FallDown(event);
                log.info("跌倒报警触发=====>", JSON.toJSONString(event));
            } else if (bed.getSubStatus() - Bed.SUB_STATUS_EXIST_NONE != data.getExist()) {
                // 状态变化
                bedUpdate.setSubStatus(Bed.SUB_STATUS_EXIST_NONE + data.getExist());
                isUpdate = true;
                isPush = true;
            }
        } else {
            if (data.getL2() == 0) {
                // 状态恢复
                bedUpdate.setStatus(Bed.STATUS_NORMAL);
//                bedUpdate.setSubStatus(Bed.SUB_STATUS_EXIST_NONE + data.getL2());
                bedUpdate.setSubStatus(Bed.SUB_STATUS_EXIST_SOMEONE + data.getL2());
                bedUpdate.setEventId(null);
                bedUpdate.setHappenTime(null);
                isUpdate = true;
                isPush = true;
                // 更新事件表，记录是否遗漏事件
                eventProcService.saveMissedEvent(bed.getEventId());
            }
        }
        if (isUpdate) {
            // 更新床位信息
            bedUpdate.setId(bed.getId());
            this.updateById(bedUpdate);
        }
        if (isPush) {
            // 推送床位当前状态
            this.pushBedCurStatus(bed.getId());
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void procAlarmEvent(Event event, Integer subStatus) {
        log.info("procAlarmEvent param:{}", event);
        // 获取当前监测时段
        BedMonitorTimeVO bedCurMonitorTime = this.getBedCurMonitorTime(event.getBedId());
        if (bedCurMonitorTime == null) {
//            log.info("procAlarmEvent 非监测时段");
            return;
        }

        Bed bed = this.baseMapper.selectById(event.getBedId());
        if (bed == null) {
            log.warn("procAlarmEvent 床位不存在 bedId:{}", event.getBedId());
            return;
        }
        if (bed.getIsRadarOnline() == Bed.RADAR_OFFLINE
                || bed.getIsRadarOn() == Bed.RADAR_OFF || bed.getStatus() == Bed.STATUS_ALARM) {
            log.info("procAlarmEvent 监测仪离线、监测仪关闭或者已经报警 bed:{}", bed);
            return;
        }

        // 新增事件
        event.setTenantId(bed.getTenantId());
        event.setContent("离床过久");
        eventService.save(event);
        // 新增事件处理
        EventProc eventProc = new EventProc();
        eventProc.setEventId(event.getId());
        eventProc.setBedId(event.getBedId());
        eventProc.setHappenTime(event.getHappenTime());
        eventProc.setStatus(EventProc.STATUS_HAPPEN);
        eventProc.setTenantId(bed.getTenantId());
        eventProcService.save(eventProc);
        // 待接单事件放入缓冲
        this.addWaitTakeEventCache(new EventBedBO(event.getId(), bed.getId(), bed.getTenantId()));
        // 修改床位状态
        Bed bedUpdate = new Bed();
        bedUpdate.setId(bed.getId());
        bedUpdate.setStatus(Bed.STATUS_ALARM);
        bedUpdate.setSubStatus(subStatus);
        bedUpdate.setEventId(event.getId());
        this.baseMapper.updateById(bedUpdate);
        // 记录事件日志
        eventLogService.procEventLog(bed.getId(), null, event.getId(), EventEnum.ALARM_OUT_BED.getCode(), null, bed.getTenantId());
        // 推送床位当前状态
        this.pushBedCurStatus(bed.getId());

        // 复星报警信息推送
        if (event.getTenantId().equals(fuXingProperties.getTenantId())) {
            AlarmInfoEvent alarmInfoEvent = new AlarmInfoEvent(this.applicationContext);
            alarmInfoEvent.setEventId(event.getId());
            applicationContext.publishEvent(alarmInfoEvent);
            log.info("procAlarmEvent send fuxing alarm event: {}", alarmInfoEvent);
        }
    }

    private void procAlarmEvent4FallDown(Event event) {
        log.info("procAlarmEvent4FallDown param:{}", event);

        Bed bed = this.baseMapper.selectById(event.getBedId());
        if (bed == null) {
            log.warn("procAlarmEvent4FallDown 床位不存在 bedId:{}", event.getBedId());
            return;
        }

        // 新增事件
        eventService.save(event);
        // 新增事件处理
        EventProc eventProc = new EventProc();
        eventProc.setEventId(event.getId());
        eventProc.setBedId(event.getBedId());
        eventProc.setHappenTime(event.getHappenTime());
        eventProc.setStatus(EventProc.STATUS_HAPPEN);
        eventProc.setTenantId(bed.getTenantId());
        eventProcService.save(eventProc);
        // 待接单事件放入缓冲
        this.addWaitTakeEventCache(new EventBedBO(event.getId(), bed.getId(), bed.getTenantId()));
        // 修改床位状态
        Bed bedUpdate = new Bed();
        bedUpdate.setId(bed.getId());
        bedUpdate.setStatus(Bed.STATUS_ALARM);
        bedUpdate.setSubStatus(Bed.SUB_STATUS_FALL_DOWN);
        bedUpdate.setEventId(event.getId());
        bedUpdate.setHappenTime(event.getHappenTime());
        this.baseMapper.updateById(bedUpdate);
        // 记录事件日志
        eventLogService.procEventLog(bed.getId(), null, event.getId(), EventEnum.ALARM_FALL_DOWN.getCode(), null, bed.getTenantId());
        // 推送床位当前状态
        this.pushBedCurStatus(bed.getId());
    }

    /**
     * 添加待接单事件到缓冲
     *
     * @param eventBedBO
     */
    private void addWaitTakeEventCache(EventBedBO eventBedBO) {
        try {
            Integer timeout = systemConfigService.getTakeEventTimeoutRedisCache(eventBedBO.getTenantId());
            if (timeout == 0) {
                timeout = 3;
            }
            long score = timeout + System.currentTimeMillis() / 1000;
            redisService.zadd(CommonConstant.WAIT_TAKE_EVENT_ZSET_PREFIX,
                    (double) score, JsonUtils.objectToJson(eventBedBO));
        } catch (Exception e) {
            log.error("addWaitTakeEventCache error eventBedBO:{}", eventBedBO, e);
        }
    }

    /**
     * 清除缓存中待接单事件
     *
     * @param eventBedBO
     */
    @Override
    public void delWaitTakeEventCache(EventBedBO eventBedBO) {
        try {
            redisService.zrem(CommonConstant.WAIT_TAKE_EVENT_ZSET_PREFIX, JsonUtils.objectToJson(eventBedBO));
        } catch (Exception e) {
            log.error("delWaitTakeEventCache error eventBedBO:{}", eventBedBO, e);
        }
    }

    /**
     * 根据条件分页查询床
     *
     * @param healthQO
     * @return
     */
    @Override
    public IPage<HealthVO> getHealth(HealthSearchParam healthQO) {
        Page<Bed> page = new Page<>(healthQO.getPageNum(), healthQO.getPageSize());

        IPage<Bed> bedShowVOIPage = this.baseMapper.selectPage(page, Wrappers.<Bed>lambdaQuery()
                .eq(healthQO.getBuildingId() != null, Bed::getBuildingId, healthQO.getBuildingId())
                .eq(healthQO.getFloorId() != null, Bed::getFloorId, healthQO.getFloorId())
                .eq(healthQO.getRoomId() != null, Bed::getRoomId, healthQO.getRoomId()));

        List<Bed> records = bedShowVOIPage.getRecords();
        List<HealthVO> healthVOS = new ArrayList<>();
        for (Bed hv : records) {
            HealthVO healthVO = new HealthVO();
            String bName = buildingService.getBaseMapper().selectById(hv.getBuildingId()).getName();
            String fName = floorService.getBaseMapper().selectById(hv.getFloorId()).getName();
            String rName = roomService.getBaseMapper().selectById(hv.getRoomId()).getName();
            healthVO.setBedName(bName + fName + rName + hv.getName());
            healthVO.setBedId(hv.getId());
            healthVOS.add(healthVO);
        }
        Page<HealthVO> bedHealthVOIPage = new Page<>();
        BeanUtils.copyProperties(bedShowVOIPage, bedHealthVOIPage);

        bedHealthVOIPage.setRecords(healthVOS);

        /*bedHealthVOIPage.setCurrent(bedShowVOIPage.getCurrent());
        bedHealthVOIPage.setPages(bedShowVOIPage.getPages());
        bedHealthVOIPage.setSize(bedShowVOIPage.getSize());
        bedHealthVOIPage.setTotal(bedShowVOIPage.getTotal());*/
        return bedHealthVOIPage;
    }

    /**
     * 查询床楼层房间名称
     *
     * @param bedId
     * @return
     */
    @Override
    public HealthVO getSleepReport(Integer bedId) {
        Bed bed = baseMapper.selectById(bedId);
        HealthVO healthVO = new HealthVO();
        String bName = buildingService.getBaseMapper().selectById(bed.getBuildingId()).getName();
        String fName = floorService.getBaseMapper().selectById(bed.getFloorId()).getName();
        String rName = roomService.getBaseMapper().selectById(bed.getRoomId()).getName();
        healthVO.setBedName(bName + fName + rName + bed.getName());
        healthVO.setBedId(bed.getId());
        return healthVO;
    }

    /**
     * 根据房间id查询床
     *
     * @param roomId
     * @return
     */
    @Override
    public CommonRes<List<Bed>> getBedByRoomId(Integer roomId) {
        return CommonRes.ok(baseMapper.selectList(Wrappers.<Bed>lambdaUpdate().eq(Bed::getRoomId, roomId)));
    }

    @Override
    public List<Bed> getBedByFloorId(Integer floorId) {
        return baseMapper.selectList(Wrappers.<Bed>lambdaUpdate().eq(Bed::getFloorId, floorId));
    }

    @Override
    public List<Bed> getBedByBuildingId(Integer buildingId) {
        return baseMapper.selectList(Wrappers.<Bed>lambdaUpdate().eq(Bed::getBuildingId, buildingId));
    }

    /**
     * 修改床的 离床阀值时间
     *
     * @param bedId
     * @param outBedTimeout
     * @return
     */
    @Override
    public Boolean updateOutBedTime(Integer bedId, String outBedTimeout) {
        Bed bed = new Bed();
        bed.setId(bedId);
        bed.setOutBedTimeout(outBedTimeout);
        int count = baseMapper.updateById(bed);
        if (count > 0) {
            try {
                // 如果床位正处于离床状态修改为最新的离床时间
                Double score = redisService.zscore(CommonConstant.OUT_BED_ZSET_PREFIX, String.valueOf(bedId));
                if (score != null) {
                    int nowTimeSecond = (int) (System.currentTimeMillis() / 1000);
                    LocalTime time = LocalTime.parse(bed.getOutBedTimeout());
                    int secondVal = time.toSecondOfDay();
                    if (score.intValue() - nowTimeSecond > 3 && score.intValue() - nowTimeSecond > secondVal) {
                        int expire = nowTimeSecond + secondVal;
                        redisService.zadd(CommonConstant.OUT_BED_ZSET_PREFIX, (double) expire, String.valueOf(bedId));
                    }
                }
            } catch (RedisConnectException e) {
                log.error("updateOutBedTime error", e);
            }
            return true;
        }
        return false;
    }

    @Override
    public Bed getBedBySn(String sn) {
        return baseMapper.selectBySn(sn);
    }

    /**
     * 获取监控基本信息（返回开关状态和监测时间段信息）
     *
     * @param bedId
     * @return
     */
    @Override
    public CommonRes<MonitorInfoVO> getMonitorInfo(Integer bedId) {
        Bed bed = baseMapper.selectById(bedId);
        if (bed == null) {
            return CommonRes.failed("床位不存在");
        }
        List<BedMonitorTimeVO> bedMonitorTimeList = bedMonitorTimeService.getBedMonitorTimeList(bedId);
        MonitorInfoVO monitorInfoVO = new MonitorInfoVO();
        monitorInfoVO.setOnOff(bed.getIsRadarOn());
        monitorInfoVO.setTimePeriods(bedMonitorTimeList);
        monitorInfoVO.setRemarks(bed.getRemarks());
        monitorInfoVO.setUserRemarks(bed.getUserRemarks());
        return CommonRes.ok(monitorInfoVO);
    }

    /**
     * 处理设备状态变化
     *
     * @param bed
     * @param devStatus
     */
    private void prodDeviceStatus(Bed bed, Integer devStatus) {
        boolean isUpdate = false;
        boolean isLog = false;
        boolean isPush = false;
        int eventType = 0;
        Bed bedUpdate = new Bed();
        if (RadarMessage.STATUS_ONLINE == devStatus) {  //设备在线
            if (bed.getIsRadarOnline() == Bed.RADAR_OFFLINE) {
                //修改床位设备在线状态
                bedUpdate.setIsRadarOnline(Bed.RADAR_ONLINE);
                //恢复离床计时
                if (bed.getStatus() == Bed.STATUS_NORMAL) {
                    this.resumeOutBedTime(bed);
                }
                isUpdate = true;
                isLog = true;
                isPush = true;
                eventType = EventEnum.MONITOR_ONLINE.getCode();
            }
        } else if (RadarMessage.STATUS_OFFLINE == devStatus) {
            if (bed.getIsRadarOnline() == Bed.RADAR_ONLINE) {
                //修改床位设备离线状态
                bedUpdate.setIsRadarOnline(Bed.RADAR_OFFLINE);
                isUpdate = true;
                isLog = true;
                isPush = true;
                eventType = EventEnum.MONITOR_OFFLINE.getCode();
                //清除离床计时
                delOutBedPending(bed.getId());
                bedUpdate.setHappenTime(null);
                bedUpdate.setId(bed.getId());

                this.baseMapper.recoveryBedById(bedUpdate);
                // 清雷健康小程序开发增加设备离线将正在进行的心跳和呼吸事件变为漏掉状态
                eventProcService.procEvent2MissedStatus4Hmp(bed.getId());
            }
        }
        if (isUpdate) {
            // 更新床位信息
            bedUpdate.setId(bed.getId());
            this.updateById(bedUpdate);
        }
        if (isLog) {
            // 记录事件日志并推送消息
            eventLogService.procEventLog(bed.getId(), null, null, eventType, null, bed.getTenantId());
        }
        if (isPush) {
            // 推送床位当前状态
            BedStatusVO bedStatusVO = getBedStatusById(bed.getId());
            if (bedStatusVO != null) {
                log.info("prodDeviceStatus push bedStatusVO:{}", bedStatusVO);
                eventWsService.pushBedStatusMsg(bedStatusVO);
            }
        }
    }

    private void procUserData(Bed bed, RadarUserDataDTO data) {
        // 监测仪关闭状态不处理监测仪数据
        if (bed.getIsRadarOn() == Bed.RADAR_OFF) {
            log.info("procUserData radar off bedId: {}", bed.getId());
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("id", bed.getId());
            queryWrapper.eq("is_deleted", 0);
            Bed bedTmp = baseMapper.selectOne(queryWrapper);

            if (bedTmp != null && bedTmp.getIsRadarOnline() == Bed.RADAR_OFFLINE) {
                //检测仪关闭恢复在线状态
                Bed bedUpdate = new Bed();
                eventLogService.procEventLog(bed.getId(), null, null, EventEnum.MONITOR_ONLINE.getCode(), null, bed.getTenantId());
                bedUpdate.setId(bed.getId());
                bedUpdate.setIsRadarOnline(Bed.RADAR_ONLINE);
                this.updateById(bedUpdate);

                //给前端推送消息
                Building building = buildingService.getById(bed.getBuildingId());
                BedStatusVO bedStatusVO = this.getBedStatusById(bed.getId());
                bedStatusVO.setBedName(getBedName(bed.getId()));
                if (building != null) {
                    bedStatusVO.setBuildingName(building.getName());
                }
                bedStatusVO.setStatus(4);
                bedStatusVO.setStatusName("监测已关闭");
                bedStatusVO.setSubStatus(2);
                eventWsService.pushBedStatusMsg(bedStatusVO);
            }

            return;
        }
        Bed bedUpdate = new Bed();
        boolean isUpdate = false;
        boolean isPush = false;
        boolean isLog = false;
        int eventType = 0;

        if (bed.getIsRadarOnline() == Bed.RADAR_OFFLINE) {
            bedUpdate.setIsRadarOnline(Bed.RADAR_ONLINE);
//            bedUpdate.setSubStatus(data.getS2()+1);
            if (bed.getStatus() == Bed.STATUS_NORMAL
                    && bed.getSubStatus() != null && bed.getSubStatus() == data.getS2() + 1) {
                this.resumeOutBedTime(bed);
            }
            // 记录事件日志 雷达上线
            eventLogService.procEventLog(bed.getId(), null, null, EventEnum.MONITOR_ONLINE.getCode(), null, bed.getTenantId());
            isUpdate = true;
            isPush = true;
        }
        if (bed.getStatus() == Bed.STATUS_NORMAL) {  //正常情况下的更新
            // 如果子状态有变化,修改状态
            if (bed.getSubStatus() == null || data.getS2() + 1 != bed.getSubStatus()) {
                bedUpdate.setSubStatus(data.getS2() + 1);
                isUpdate = true;
                isPush = true;
                if (bed.getSubStatus() != null && bed.getSubStatus() == Bed.SUB_STATUS_OUT_BED) {
                    // 清除Redis离床计时
                    delOutBedPending(bed.getId());
                    bedUpdate.setHappenTime(null);
                } else if (bedUpdate.getSubStatus() == Bed.SUB_STATUS_OUT_BED) {
                    LocalDateTime now = LocalDateTime.now();
                    bedUpdate.setHappenTime(now);
                    // 启动Redis离床计时
                    addOutBedPending(bed.getId(), true);
                    isLog = true;
                    eventType = getNormalEventType(bedUpdate.getSubStatus());
                }
            }
        } else {
            if (data.getS2() + 1 != Bed.SUB_STATUS_OUT_BED) {
                bedUpdate.setStatus(Bed.STATUS_NORMAL);
                bedUpdate.setSubStatus(data.getS2() + 1);
                bedUpdate.setEventId(null);
                // 清除Redis离床计时
                delOutBedPending(bed.getId());
                bedUpdate.setHappenTime(null);
                isUpdate = true;
                isPush = true;

                EventBedBO eventBedBO = new EventBedBO();
                eventBedBO.setBedId(bed.getId());
                eventBedBO.setEventId(bed.getEventId());
                eventBedBO.setTenantId(bed.getTenantId());
                this.delWaitTakeEventCache(eventBedBO);

                // 更新事件表，记录是否遗漏事件
                eventProcService.saveMissedEvent(bed.getEventId());

            }
        }
        if (isUpdate) {
            // 更新床位信息
            bedUpdate.setId(bed.getId());
            this.updateById(bedUpdate);
        }
        if (isLog) {
            // 记录事件并推送床位消息
            eventLogService.procEventLog(bed.getId(), null, null, eventType, null, bed.getTenantId());
        }
        if (isPush) {
            // 推送床位当前状态
            this.pushBedCurStatus(bed.getId());
        }
    }

    /**
     * 加入离床异常待定区
     *
     * @param bedId
     * @param isForce 是否强制更新 true-强制 false-非强制
     */
    private void addOutBedPending(Integer bedId, Boolean isForce) {
        try {
            if (!isForce) {
                Double score = redisService.zscore(CommonConstant.OUT_BED_ZSET_PREFIX, String.valueOf(bedId));
                if (score != null) {
                    return;
                }
            }
            long expire = System.currentTimeMillis() / 1000 + this.getBedOutBedTimeout(bedId, OUT_BED_TIMEOUT_DEF);
            redisService.zadd(CommonConstant.OUT_BED_ZSET_PREFIX, (double) expire, String.valueOf(bedId));
        } catch (RedisConnectException e) {
            log.error("addOutBedPending error", e);
        }
    }

    /**
     * 获取离床超时时间
     *
     * @param bedId  床位ID
     * @param defVal 默认值
     * @return 单位秒
     */
    private int getBedOutBedTimeout(Integer bedId, int defVal) {
        int secondVal = defVal;
        try {
            // 使用全局设置
//            Bed bed = this.getById(bedId);
//            Integer tenantId = TenantContextHolder.getTenantId();
//            TenantContextHolder.setTenantId(bed.getTenantId());
//            LocalTime time = LocalTime.parse(systemConfigService.getOutBedTimeout());
//            TenantContextHolder.setTenantId(tenantId);
//            secondVal = time.toSecondOfDay();

            Bed bed = this.getById(bedId);
            if (bed != null && StringUtils.isNotEmpty(bed.getOutBedTimeout())) {
                LocalTime time = LocalTime.parse(bed.getOutBedTimeout());
                secondVal = time.toSecondOfDay();
                if (secondVal == 0) {
                    secondVal = 3;
                }
            }
        } catch (Exception e) {
            log.warn("getBedOutBedTimeout 错误 bedId:{}", bedId, e);
        }
        log.info("getBedOutBedTimeout return;{}", secondVal);
        return secondVal;
    }

    /**
     * 从离床待定区删除
     *
     * @param bedId
     */
    private void delOutBedPending(Integer bedId) {
        try {
            redisService.zrem(CommonConstant.OUT_BED_ZSET_PREFIX, String.valueOf(bedId));
        } catch (RedisConnectException e) {
            log.error("delOutBedPending error", e);
        }
    }

    /**
     * 通过子状态获取事件类型
     *
     * @param subStatus
     * @return
     */
    public static Integer getNormalEventType(Integer subStatus) {
        Integer eventType = null;
        switch (subStatus) {
            case Bed.SUB_STATUS_OUT_BED:
                eventType = EventEnum.SLEEP_STATUS_OUT_BED.getCode();
                break;
            case Bed.SUB_STATUS_CLEAR:
                eventType = EventEnum.SLEEP_STATUS_CLEAR.getCode();
                break;
            case Bed.SUB_STATUS_LIGHT_SLEEP:
                eventType = EventEnum.SLEEP_STATUS_LIGHT.getCode();
                break;
            case Bed.SUB_STATUS_DEEP_SLEEP:
                eventType = EventEnum.SLEEP_STATUS_DEEP.getCode();
                break;
        }
        return eventType;
    }

    /**
     * 获取指定床位当前状态
     *
     * @param bedId
     * @return
     */
    @Override
    public BedStatusVO getBedStatusById(Integer bedId) {
        BedStatusBO bedStatusBO = this.baseMapper.selectBedStatusById(bedId);
        if (bedStatusBO == null) {
            return null;
        }
        BedStatusVO bedStatusVO = new BedStatusVO();
        BeanUtils.copyProperties(bedStatusBO, bedStatusVO);
        setByStatus(bedStatusBO, bedStatusVO);
        return bedStatusVO;
    }

    /**
     * 推送床位当前状态消息
     *
     * @param bedId
     */
    @Override
    public void pushBedCurStatus(Integer bedId) {
        this.pushBedCurStatus(bedId, true);
    }

    /**
     * 推送床位当前状态消息
     *
     * @param bedId
     * @param isForce 是否强制推送，false时如果当前状态为报警状态不推送
     */
    @Override
    public void pushBedCurStatus(Integer bedId, boolean isForce) {
        // 推送床位当前状态
        BedStatusVO bedStatusVO = getBedStatusById(bedId);
        if (bedStatusVO == null) {
            return;
        }
        if (!isForce && bedStatusVO.getStatus() == 5) {
            return;
        }
        log.info("pushBedCurStatus push bedStatusVO:{}", bedStatusVO);
        eventWsService.pushBedStatusMsg(bedStatusVO);
    }

    public String getBedName(Integer bedId) {
        BedBO bedFullName = this.getBedFullName(bedId);
        String name = "";
        if (bedFullName != null) {
            name = bedFullName.getFloorName() + "-" + bedFullName.getRoomName() + "-" + bedFullName.getBedName();
        }
        return name;
    }

    /**
     * 载入床位监控时段到redis
     *
     * @throws RedisConnectException
     */
    @Override
    public void loadBedMonitorTimeRedisCache() throws RedisConnectException {
        Page<Bed> bedPage = new Page<>();
        bedPage.setSize(100);
        while (true) {
            IPage<Bed> bedIPage = baseMapper.selectPage(bedPage, Wrappers.emptyWrapper());
            List<Bed> bedList = bedIPage.getRecords();
            if (CollectionUtils.isEmpty(bedList)) {
                break;
            }
            log.info("loadBedMonitorTimeRedisCache current:{},size:{}", bedIPage.getCurrent(), bedList.size());
//            List<Bed> bedList = baseMapper.selectList(Wrappers.<Bed>lambdaQuery().select(Bed::getId));
            for (Bed bed : bedList) {
                List<BedMonitorTimeVO> bedMonitorTimeList = bedMonitorTimeService.getBedMonitorTimeList(bed.getId());
                boolean isExistCurMonitorTime = false;
                for (BedMonitorTimeVO bedMonitorTimeVO : bedMonitorTimeList) {
                    if (this.addBetMonitorTime(bed, bedMonitorTimeVO)) {
                        isExistCurMonitorTime = true;
                    }
                }
                // 如果不存在当前监测时间段
                if (!isExistCurMonitorTime) {
                    // 删除缓存中的床位当前时段
                    this.delBedCurMonitorTime(bed.getId());
//                if (bed.getMonitorTimeId() != 0) {
//                    // 同步床位表监测时段ID
//                    bed.setMonitorTimeId(0);
//                    this.updateById(bed);
//                }
                }
            }
            bedPage.setCurrent(bedPage.getCurrent() + 1);
        }
    }

    /**
     * 添加床位监测时间段到缓存
     *
     * @param bedMonitorTime
     * @return 是否是当前监测时间段
     * @throws RedisConnectException
     */
    @Override
    public void addBetMonitorTime(BedMonitorTime bedMonitorTime) throws RedisConnectException {
        Bed bed = this.baseMapper.selectById(bedMonitorTime.getBedId());
        BedMonitorTimeVO bedMonitorTimeVO = new BedMonitorTimeVO();
        BeanUtils.copyProperties(bedMonitorTime, bedMonitorTimeVO);
        this.addBetMonitorTime(bed, bedMonitorTimeVO);
    }

    /**
     * 更新床位监测时间段缓存
     *
     * @param oldBedMonitorTime
     * @param newBedMonitorTime
     * @throws RedisConnectException
     */
    @Override
    public void updateBetMonitorTime(BedMonitorTime oldBedMonitorTime, BedMonitorTime newBedMonitorTime) throws RedisConnectException {
        Bed bed = this.baseMapper.selectById(oldBedMonitorTime.getBedId());
        BedMonitorTimeVO bedMonitorTimeVOOld = new BedMonitorTimeVO();
        BeanUtils.copyProperties(oldBedMonitorTime, bedMonitorTimeVOOld);
        this.delBetMonitorTime(bed, bedMonitorTimeVOOld);

        BedMonitorTimeVO bedMonitorTimeVONew = new BedMonitorTimeVO();
        BeanUtils.copyProperties(newBedMonitorTime, bedMonitorTimeVONew);
        this.addBetMonitorTime(bed, bedMonitorTimeVONew);
    }

    /**
     * 删除床位监测时间段缓存
     *
     * @param bedMonitorTime
     * @throws RedisConnectException
     */
    @Override
    public void delBetMonitorTime(BedMonitorTime bedMonitorTime) throws RedisConnectException {
        Bed bed = this.baseMapper.selectById(bedMonitorTime.getBedId());
        BedMonitorTimeVO bedMonitorTimeVO = new BedMonitorTimeVO();
        BeanUtils.copyProperties(bedMonitorTime, bedMonitorTimeVO);
        this.delBetMonitorTime(bed, bedMonitorTimeVO);
    }

    /**
     * 删除床位监测时间段缓存
     *
     * @param bed
     * @param bedMonitorTimeVO
     * @throws RedisConnectException
     */
    private void delBetMonitorTime(Bed bed, BedMonitorTimeVO bedMonitorTimeVO) throws RedisConnectException {
        this.delBedStartMonitorTime(bedMonitorTimeVO);
        this.delBedEndMonitorTime(bedMonitorTimeVO);
        BedMonitorTimeVO bedCurMonitorTime = this.getBedCurMonitorTime(bed.getId());
        if (bedCurMonitorTime != null && bedCurMonitorTime.equals(bedMonitorTimeVO)) {
            this.delBedCurMonitorTime(bed.getId());
        }
//        if (bed.getMonitorTimeId().equals(bedMonitorTimeVO.getId())) {
//            this.delBedCurMonitorTime(bedMonitorTimeVO.getBedId());
//            Bed bedUpdate = new Bed();
//            bedUpdate.setId(bed.getId());
//            bedUpdate.setMonitorTimeId(0);
//            this.updateById(bedUpdate);
//        }
    }

    /**
     * 添加床位监测时间段到缓存
     *
     * @param bed
     * @param bedMonitorTimeVO
     * @return 是否是当前监测时间段
     * @throws RedisConnectException
     */
    @Override
    public boolean addBetMonitorTime(Bed bed, BedMonitorTimeVO bedMonitorTimeVO) throws RedisConnectException {
        boolean ret = false;
        // 设置监测开始时间
        this.setBedStartMonitorTime(bedMonitorTimeVO);
        // 设置监测结束时间
        this.setBedEndMonitorTime(bedMonitorTimeVO);
        // 检查是否是当前监测时间段
        if (DateUtil.isCurTimePeriod(bedMonitorTimeVO.getStartTime(), bedMonitorTimeVO.getEndTime())) {
            ret = true;
            if (!bedMonitorTimeVO.equals(this.getBedCurMonitorTime(bed.getId()))) {
                // 设置床位当前监测时段
                this.setBedCurMonitorTime(bedMonitorTimeVO);
                // 恢复离床计时
                this.resumeOutBedTime(bed);
            }
//            if (!bed.getMonitorTimeId().equals(bedMonitorTimeVO.getId())) {
//                // 同步床位表监测时段ID
//                bed.setMonitorTimeId(bedMonitorTimeVO.getId());
//                this.updateById(bed);
//            }
        }
        return ret;
    }

    /**
     * 设置床位当前监测时间段
     *
     * @param bedMonitorTimeVO
     * @throws RedisConnectException
     */
    @Override
    public void setBedCurMonitorTime(BedMonitorTimeVO bedMonitorTimeVO) throws RedisConnectException {
        redisService.hset(CommonConstant.BED_CUR_MONITOR_TIME_CACHE_PREFIX,
                String.valueOf(bedMonitorTimeVO.getBedId()), JsonUtils.objectToJson(bedMonitorTimeVO));
//        this.addOutBedPending(bedMonitorTimeVO.getBedId(), false);
    }

    /**
     * 删除床位当前监测时间段
     *
     * @param bedId
     * @throws RedisConnectException
     */
    @Override
    public void delBedCurMonitorTime(Integer bedId) throws RedisConnectException {
        redisService.hdel(CommonConstant.BED_CUR_MONITOR_TIME_CACHE_PREFIX,
                String.valueOf(bedId));
    }

    /**
     * 设置床位监测开始时间段
     *
     * @param bedMonitorTimeVO
     * @throws RedisConnectException
     */
    private void setBedStartMonitorTime(BedMonitorTimeVO bedMonitorTimeVO) throws RedisConnectException {
        String startTime = bedMonitorTimeVO.getStartTime();
        LocalTime localTimeStart = LocalTime.parse(startTime);
        if (localTimeStart.isAfter(LocalTime.now())) {
            LocalDateTime localDateTime = LocalDateTime.of(LocalDate.now(), localTimeStart);
            long timestampStart = localDateTime.toEpochSecond(ZoneOffset.of("+8"));
            redisService.zadd(CommonConstant.BED_MONITOR_TIME_START_ZSET_PREFIX,
                    (double) timestampStart, JsonUtils.objectToJson(bedMonitorTimeVO));
        } else {
            LocalDateTime localDateTime = LocalDateTime.of(LocalDate.now().plusDays(1), localTimeStart);
            long timestampStart = localDateTime.toEpochSecond(ZoneOffset.of("+8"));
            redisService.zadd(CommonConstant.BED_MONITOR_TIME_START_ZSET_PREFIX,
                    (double) timestampStart, JsonUtils.objectToJson(bedMonitorTimeVO));
        }
    }

    /**
     * 删除床位监测开始时间段
     *
     * @param bedMonitorTimeVO
     * @throws RedisConnectException
     */
    private void delBedStartMonitorTime(BedMonitorTimeVO bedMonitorTimeVO) throws RedisConnectException {
        redisService.zrem(CommonConstant.BED_MONITOR_TIME_START_ZSET_PREFIX, JsonUtils.objectToJson(bedMonitorTimeVO));
    }

    /**
     * 删除床位监测结束时间段
     *
     * @param bedMonitorTimeVO
     * @throws RedisConnectException
     */
    private void delBedEndMonitorTime(BedMonitorTimeVO bedMonitorTimeVO) throws RedisConnectException {
        redisService.zrem(CommonConstant.BED_MONITOR_TIME_END_ZSET_PREFIX, JsonUtils.objectToJson(bedMonitorTimeVO));
    }

    /**
     * 设置床位监测结束时间段
     *
     * @param bedMonitorTimeVO
     * @throws RedisConnectException
     */
    private void setBedEndMonitorTime(BedMonitorTimeVO bedMonitorTimeVO) throws RedisConnectException {
        String endTime = bedMonitorTimeVO.getEndTime();
        // 结束时间减1秒
        LocalTime localTimeEnd = LocalTime.parse(endTime).minusSeconds(1);
        if (localTimeEnd.isAfter(LocalTime.now())) {
            LocalDateTime localDateTime = LocalDateTime.of(LocalDate.now(), localTimeEnd);
            long timestampStart = localDateTime.toEpochSecond(ZoneOffset.of("+8"));
            redisService.zadd(CommonConstant.BED_MONITOR_TIME_END_ZSET_PREFIX,
                    (double) timestampStart, JsonUtils.objectToJson(bedMonitorTimeVO));
        } else {
            LocalDateTime localDateTime = LocalDateTime.of(LocalDate.now().plusDays(1), localTimeEnd);
            long timestampStart = localDateTime.toEpochSecond(ZoneOffset.of("+8"));
            redisService.zadd(CommonConstant.BED_MONITOR_TIME_END_ZSET_PREFIX,
                    (double) timestampStart, JsonUtils.objectToJson(bedMonitorTimeVO));
        }
    }

    /**
     * 获取床位当前监测时间段
     *
     * @param bedId
     * @return
     */
    @Override
    public BedMonitorTimeVO getBedCurMonitorTime(Integer bedId) {
        BedMonitorTimeVO bedMonitorTimeVO = null;
        try {
            String strVO = redisService.hget(CommonConstant.BED_CUR_MONITOR_TIME_CACHE_PREFIX, String.valueOf(bedId));
            if (strVO != null) {
                bedMonitorTimeVO = JsonUtils.jsonToBean(strVO, BedMonitorTimeVO.class);
            }
        } catch (Exception e) {
            log.error("getBedCurMonitorTime error, bedId:{}", bedId, e);
        }
        return bedMonitorTimeVO;
    }

    /**
     * 床位监测时间段结束时的处理
     *
     * @param bedMonitorTimeVO
     */
    @Override
    public void procBedMonitorTimeEnd(BedMonitorTimeVO bedMonitorTimeVO) throws RedisConnectException {
        // 重置为下一次触发时间
        this.setBedEndMonitorTime(bedMonitorTimeVO);
        // 删除缓存中的床位当前时段
        this.delBedCurMonitorTime(bedMonitorTimeVO.getBedId());
        // 处理床位状态
        this.procBedMonitorTime(bedMonitorTimeVO, EventEnum.MONITOR_TIME_END.getCode());
    }

    /**
     * 床位监测时间段开始时的处理
     *
     * @param bedMonitorTimeVO
     */
    @Override
    public void procBedMonitorTimeStart(BedMonitorTimeVO bedMonitorTimeVO) throws RedisConnectException {
        // 重置为下一次触发时间
        this.setBedStartMonitorTime(bedMonitorTimeVO);
        // 设置床位当前监测时段
        this.setBedCurMonitorTime(bedMonitorTimeVO);
        // 处理床位状态
        this.procBedMonitorTime(bedMonitorTimeVO, EventEnum.MONITOR_TIME_START.getCode());
    }

    /**
     * 获取床位信息并带有监测仪SN码
     *
     * @param bedId
     * @return
     */

    @Override
    public BedRadarBO getBedWithSn(Integer bedId) {
        return baseMapper.selectBedWithSn(bedId);
    }

    private void procBedMonitorTime(BedMonitorTimeVO bedMonitorTimeVO, Integer eventType) {
        Bed bed = this.baseMapper.selectById(bedMonitorTimeVO.getBedId());
        boolean isPush = false;
        boolean isLog = false;
        if (Bed.RADAR_OFFLINE != bed.getIsRadarOnline() && Bed.RADAR_OFF != bed.getIsRadarOn()) {
            isPush = true;
            isLog = true;
        }
        if (isLog) {
            // 记录事件并推送床位消息
            eventLogService.procEventLog(bed.getId(), null, null, eventType, null, bed.getTenantId());
        }
        if (isPush) {
            // 推送床位当前状态
            this.pushBedCurStatus(bed.getId());
            // 如果是离床状态
            if (bed.getStatus() == Bed.STATUS_NORMAL && bed.getSubStatus() == Bed.SUB_STATUS_OUT_BED) {
                // 启动Redis离床计时
                addOutBedPending(bed.getId(), false);
            }
        }
    }

    /**
     * 恢复离床计时
     *
     * @param bed
     */
    private void resumeOutBedTime(Bed bed) {
        log.info("resumeOutBedTime in bed:{}", bed);
        if (bed.getIsRadarOnline() == Bed.RADAR_OFFLINE) {
            return;
        }
        if (bed.getIsRadarOn() == Bed.RADAR_OFF) {
            return;
        }
        if (bed.getStatus() != Bed.STATUS_NORMAL || bed.getSubStatus() != Bed.SUB_STATUS_OUT_BED) {
            return;
        }
        // 获取当前监测时段
        BedMonitorTimeVO bedCurMonitorTime = this.getBedCurMonitorTime(bed.getId());
        // 如果在监测时段内
        if (bedCurMonitorTime != null) {
            // 启动Redis离床计时
            addOutBedPending(bed.getId(), false);
        }
    }

    @Override
    public List<BedStatusVO> getAllBeds(Long userId, Integer roleId, Integer tenantId) {
        List<BedStatusVO> resList = new ArrayList<>();
        List<Integer> bedIdsByUser = this.getBedIdsByUser(userId, roleId);
        if (CollectionUtils.isEmpty(bedIdsByUser) || bedIdsByUser.get(0) == 0) {
            return resList;
        }
        if (bedIdsByUser.get(0) == -1) {
            bedIdsByUser = null;
        }

        List<BedStatusBO> bedStatusBOS = this.baseMapper.selectBedStatusListByIds(bedIdsByUser, tenantId);
        bedStatusBOS.forEach(bedStatusBO -> {
            BedStatusVO bedStatusVO = new BedStatusVO();
            BeanUtils.copyProperties(bedStatusBO, bedStatusVO);
            setByStatus(bedStatusBO, bedStatusVO);

            if (bedStatusBO.getHealthyBpm() != null) {
                switch (bedStatusBO.getHealthyBpm()) {
                    case 3:
                        bedStatusVO.setHealthyStatusName("呼吸正常");
                        break;
                    case 4:
                        bedStatusVO.setHealthyStatusName("呼吸过速");
                        break;
                    case 5:
                        bedStatusVO.setHealthyStatusName("呼吸暂停过久");
                        break;
                    case 6:
                        bedStatusVO.setHealthyStatusName("心跳正常");
                        break;
                    case 7:
                        bedStatusVO.setHealthyStatusName("心跳过速");
                        break;
                    case 8:
                        bedStatusVO.setHealthyStatusName("心跳过缓");
                        break;
                    default:
                }
            }
            // 设置遗漏任务数量
//            bedStatusVO.setMissedEventNum(eventProcService.getMissedEventNumByBed(bedStatusVO.getBedId()));
            resList.add(bedStatusVO);
        });

        return resList;
    }

    @Override
    public void procRadarDataV4(RadarMessage message) {
        String sn = message.getSn();
        Bed bed = this.baseMapper.selectBySn(message.getSn());
        if (bed == null) {
            log.debug("procRadarData not bind bed sn: {}", message.getSn());
            return;
        }

        //设备状态
        if (message.getType() == RadarMessage.TYPE_DEVICE_STATUS) {

        } else if (message.getType() == RadarMessage.TYPE_USER_DATA) {  //用户数据
            this.procUserDataV4(bed, (RadarUserDataFour) message.getData());
        } else if (message.getType() == RadarMessage.TYPE_FALL_DOWN_DATA) {  //跌倒数据

        }
    }

    @Override
    public void procRadarDataV7(JsonNode jsonNode, Integer type) {
        String sn = jsonNode.get("SN").asText();
        Bed bed = this.baseMapper.selectBySn(sn);
        if (bed == null) {
            log.debug("procRadarDataV7 not bind bed sn: {}", sn);
            return;
        }
        //设备状态
        if (type == RadarMessage.TYPE_DEVICE_STATUS) {

        } else if (type == RadarMessage.TYPE_USER_DATA) {  //用户数据
            //构建一下数据,这里用V4的处理逻辑，看一下有没有问题
            RadarUserDataFour radarUserDataFour = new RadarUserDataFour();
            radarUserDataFour.setTCFg(jsonNode.get("TCF").asInt());//离床过近
            radarUserDataFour.setOBFg(jsonNode.get("OBF").asInt());//离床标志
            radarUserDataFour.setSn(sn);
            radarUserDataFour.setFrameNo(jsonNode.get("FRAME").asLong());
            this.procUserDataV4(bed, radarUserDataFour);
        } else if (type == RadarMessage.TYPE_FALL_DOWN_DATA) {  //跌倒数据

        }
    }

    private void procUserDataV4(Bed bed, RadarUserDataFour radarUserDataFour) {
        //log.info("------------------4.0数据进入-----------------------------", bed.getId());
        // 监测仪关闭状态不处理监测仪数据
        if (bed.getIsRadarOn() == Bed.RADAR_OFF) {
            log.info("procUserData radar off bedId: {}", bed.getId());
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("id", bed.getId());
            queryWrapper.eq("is_deleted", 0);
            Bed bedTmp = baseMapper.selectOne(queryWrapper);

            if (bedTmp != null && bedTmp.getIsRadarOnline() == Bed.RADAR_OFFLINE) {
                //检测仪关闭恢复在线状态
                Bed bedUpdate = new Bed();
                eventLogService.procEventLog(bed.getId(), null, null, EventEnum.MONITOR_ONLINE.getCode(), null, bed.getTenantId());
                bedUpdate.setId(bed.getId());
                bedUpdate.setIsRadarOnline(Bed.RADAR_ONLINE);
                this.updateById(bedUpdate);

                //给前端推送消息
                Building building = buildingService.getById(bed.getBuildingId());
                BedStatusVO bedStatusVO = this.getBedStatusById(bed.getId());
                bedStatusVO.setBedName(getBedName(bed.getId()));
                if (building != null) {
                    bedStatusVO.setBuildingName(building.getName());
                }
                bedStatusVO.setStatus(4);
                bedStatusVO.setStatusName("监测已关闭");
                bedStatusVO.setSubStatus(2);
                eventWsService.pushBedStatusMsg(bedStatusVO);
            }
            return;
        }

//        if(bed.getId()!=272){
//            return;
//        }

        Bed bedUpdate = new Bed();
        boolean isUpdate = false;
        boolean isPush = false;
        boolean isLog = false;
        int eventType = 0;

        /*分析体动检测结果标志*/
        int flagBodyMovement = 0;
        Integer thVal_sleepCompute = 3;
        Integer ThVal_1 = 3;
        if (LocalTime.now().isBefore(LocalTime.of(4, 0))) {
            thVal_sleepCompute = 8;
        }
        boolean flag = false;
        //Macro尺度体动检测滑窗左右比率 dB 值
        Double[] BMPR2 = radarUserDataFour.getBMPR2();
        if (BMPR2 != null) {
            for (int i = 1; i < BMPR2.length; i++) {
                flag = (BMPR2[i - 1] >= ThVal_1) && (BMPR2[i] < ThVal_1);
                if (flag) {
                    flagBodyMovement = 1;
                    break;
                }
            }
        }

        //这里出问题了
        Integer bodyMovementCount = flagBodyMovementMapper.selectMovementCount(bed.getId()) + flagBodyMovement;
        log.debug(bed.getId() + "-" + LocalDate.now() + " " + LocalTime.now() + "-" + bodyMovementCount);


        Integer bodyMovementSum = flagBodyMovementMapper.selectMovementSum(bed.getId()) + 1;


        long expire = System.currentTimeMillis() / 1000;

        //分析状态

        //UploadResult.TooCloseFlag
        Integer TCFg = radarUserDataFour.getTCFg(); //目标过近标志（布尔型标量，1 表示过近，0 表示正常）

        //UploadResult.OutBedFlag
        Integer OBFg = radarUserDataFour.getOBFg(); //离床标志（布尔型标量，1 表示离床，0 表示在床）

        //UploadResult.SleepingFlag
        Integer SFg = 0; //清醒
        if (bodyMovementSum >= 500 && bodyMovementCount < thVal_sleepCompute) {
            SFg = 1;  //睡觉
        } else {
            //SFg = radarUserDataFour.getSFg(); //入睡标志（布尔型标量，1 表示入睡，0 表示清醒）
        }
        //Integer SFg = radarUserDataFour.getSFg(); //入睡标志（布尔型标量，1 表示入睡，0 表示清醒）


        //UploadResult.TargetSteadyFlag
        Integer TSFg = radarUserDataFour.getTSFg(); //（布尔型标量，1 表示配合，0 表示非配合）

        //UploadResult.ApneaAlertFlag
        Integer AAFg = radarUserDataFour.getAAFg(); //窒息报警（布尔型标量，0 表示未发生窒息，1 表示发生窒息）

        Double BDEF = radarUserDataFour.getBdef();
        LocalDateTime time = LocalDateTime.now().plusSeconds(-10);


        Integer subStatusUpdate = null;  //1-离床 2-清醒 3-浅睡 4-深睡
        //功能A：无人/清醒/睡眠三状态展示
        if (TCFg == 0 && OBFg == 1) {
            //无人
            subStatusUpdate = 1;
            saveLogTest(bed, "离床", subStatusUpdate);
        }

        if (TCFg == 0 && OBFg == 0 && SFg == 1) {
            //睡眠
            subStatusUpdate = 3;
            saveLogTest(bed, "睡觉", subStatusUpdate);
        }

        if (TCFg == 1 || (TCFg == 0 && OBFg == 0 && SFg == 0)) {
            //清醒
            subStatusUpdate = 2;
            saveLogTest(bed, "清醒", subStatusUpdate);
        }

        try {
            redisService.set("logTest" + bed.getId(), String.valueOf(subStatusUpdate));
        } catch (RedisConnectException redisConnectException) {
            redisConnectException.printStackTrace();
        }

        if (subStatusUpdate != null && subStatusUpdate != 1) {
            FlagBodyMovement flagBodyMovement1 = new FlagBodyMovement();
            flagBodyMovement1.setFlagBodyMovement(flagBodyMovement);
            flagBodyMovement1.setBedId(bed.getId());
            flagBodyMovement1.setSnCode(radarUserDataFour.getSn());
            flagBodyMovement1.setFrameNo(radarUserDataFour.getFrameNo());
            flagBodyMovementMapper.insert(flagBodyMovement1);
        }


        if (bed.getIsRadarOnline() == Bed.RADAR_OFFLINE) {
            bedUpdate.setIsRadarOnline(Bed.RADAR_ONLINE);
//            bedUpdate.setSubStatus(data.getS2()+1);
            if (bed.getStatus() == Bed.STATUS_NORMAL
                    && bed.getSubStatus() != null && bed.getSubStatus().equals(subStatusUpdate)) { //离床
                this.resumeOutBedTime(bed);
            }
            // 记录事件日志 雷达上线
            eventLogService.procEventLog(bed.getId(), null, null, EventEnum.MONITOR_ONLINE.getCode(), null, bed.getTenantId());
            isUpdate = true;
            isPush = true;
        }

        if (bed.getStatus() == Bed.STATUS_NORMAL) {
            // 如果子状态有变化,修改状态
            if (bed.getSubStatus() == null || !subStatusUpdate.equals(bed.getSubStatus())) {
                bedUpdate.setSubStatus(subStatusUpdate);
                isUpdate = true;
                isPush = true;
                if (bed.getSubStatus() != null && bed.getSubStatus() == Bed.SUB_STATUS_OUT_BED) {
                    // 清除Redis离床计时
                    delOutBedPending(bed.getId());
                    bedUpdate.setHappenTime(null);
                } else if (bedUpdate.getSubStatus() == Bed.SUB_STATUS_OUT_BED) {
                    LocalDateTime now = LocalDateTime.now();
                    bedUpdate.setHappenTime(now);
                    // 启动Redis离床计时
                    addOutBedPending(bed.getId(), true);
                    isLog = true;
                    eventType = getNormalEventType(bedUpdate.getSubStatus());
                }
            }
        } else {
            if (subStatusUpdate != Bed.SUB_STATUS_OUT_BED) {
                bedUpdate.setStatus(Bed.STATUS_NORMAL);
                bedUpdate.setSubStatus(subStatusUpdate);
                bedUpdate.setEventId(null);
                // 清除Redis离床计时
                delOutBedPending(bed.getId());
                bedUpdate.setHappenTime(null);
                isUpdate = true;
                isPush = true;

                EventBedBO eventBedBO = new EventBedBO();
                eventBedBO.setBedId(bed.getId());
                eventBedBO.setEventId(bed.getEventId());
                eventBedBO.setTenantId(bed.getTenantId());
                this.delWaitTakeEventCache(eventBedBO);

                // 更新事件表，记录是否遗漏事件
                eventProcService.saveMissedEvent(bed.getEventId());
            }
        }

        if (isUpdate) {
            // 更新床位信息
            bedUpdate.setId(bed.getId());
            this.updateById(bedUpdate);
        }
        if (isLog) {
            // 记录事件并推送床位消息
            eventLogService.procEventLog(bed.getId(), null, null, eventType, null, bed.getTenantId());
        }
        if (isPush) {
            // 推送床位当前状态
            this.pushBedCurStatus(bed.getId());
        }
    }

    /**
     * 新增键值对
     *
     * @param type
     * @param expire
     * @param bedId
     * @throws RedisConnectException
     */
    private void addKey(String type, double expire, String bedId) throws RedisConnectException {
        if (redisService.zscore(type, bedId) == null) {
            redisService.zadd(type, (double) expire, bedId);
        }
    }

    /**
     * 删除键值对
     *
     * @param type
     * @param bedId
     * @throws RedisConnectException
     */
    private void removeKey(String type, String bedId) throws RedisConnectException {
        if (redisService.zscore(type, bedId) != null) {
            redisService.zrem(type, bedId);
        }
    }

    public void saveLogTest(Bed bed, String content, Integer type) {
        try {
            String oldType = redisService.get("logTest" + bed.getId());

            if (oldType != null && Integer.parseInt(oldType) == type) {
                return;
            }
            EventLogTest eventLogTest = new EventLogTest();
            eventLogTest.setBedId(bed.getId());
            eventLogTest.setEventId(0L);
            eventLogTest.setContent(content);
            eventLogTest.setTenantId(bed.getTenantId());
            eventLogTest.setCreateTime(LocalDateTime.now());
            eventLogTest.setType(type);
            eventLogTest.setName(getBedName(bed.getId()));
            eventLogTest.setTypeGroup(1);
            eventLogTestService.save(eventLogTest);
        } catch (RedisConnectException redisConnectException) {
            redisConnectException.printStackTrace();
        }
    }

    @Autowired
    private RadarService radarService;

    @Resource
    private RadarBedMapper radarBedMapper;

    @Override
    public boolean isBed(Integer bedId) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("bed_id", bedId);
        queryWrapper.eq("is_deleted", 0);
        List<RadarBed> radarBedList = radarBedMapper.selectList(queryWrapper);
        if (CollUtil.isNotEmpty(radarBedList)) {
            for (RadarBed radarBed : radarBedList) {
                if (radarBed != null) {
                    QueryWrapper queryWrapper1 = new QueryWrapper();
                    queryWrapper1.eq("id", radarBed.getRadarId());
                    queryWrapper1.eq("is_deleted", 0);
                    Radar radar = radarService.getOne(queryWrapper1);
                    if (radar != null && radar.getType() == 1) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    @Override
    public boolean isBedV1(Integer bedId) {

        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("bed_id", bedId);
        queryWrapper.eq("is_deleted", 0);
        RadarBed radarBed = radarBedMapper.selectOne(queryWrapper);
        if (radarBed != null) {
            QueryWrapper queryWrapper1 = new QueryWrapper();
            queryWrapper1.eq("id", radarBed.getRadarId());
            queryWrapper1.eq("is_deleted", 0);
            Radar radar = radarService.getOne(queryWrapper1);
            if (radar != null) {
                return true;
            }
        }

        return false;
    }

    @Override
    public boolean isMonitorTime(Integer bedId) {
        // 获取当前监测时段
        BedMonitorTimeVO bedCurMonitorTime = this.getBedCurMonitorTime(bedId);
        if (bedCurMonitorTime == null) {
//            log.info("procAlarmEvent 非监测时段");
            return false;
        }

        Bed bed = this.baseMapper.selectById(bedId);
        if (bed == null) {
            log.warn("procAlarmEvent 床位不存在 bedId:{}", bedId);
            return false;
        }
        if (bed.getIsRadarOnline() == Bed.RADAR_OFFLINE
                || bed.getIsRadarOn() == Bed.RADAR_OFF || bed.getStatus() == Bed.STATUS_ALARM) {
            log.info("procAlarmEvent 监测仪离线、监测仪关闭或者已经报警 bed:{}", bed);
            return false;
        }

        return true;
    }

    @Override
    public Bed getBedBySnNoTenantId(String snCode) {
        return baseMapper.getBedBySnNoTenantId(snCode);
    }

    @Override
    public List<RadarUpVersionVo> getOnlineRadarList(String iotProductKey, String currentVersion) {
        return baseMapper.getOnlineRadarList(iotProductKey, currentVersion);
    }
}
